﻿using Kingdee.BOS;
using Kingdee.BOS.App.Data;
using Kingdee.BOS.Core;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Util;
using LM.YF.K3Cloud.Plugin.Models;
using LM.YF.K3Cloud.Plugin.Models.Grasses;
using LM.YF.K3Cloud.Plugin.Models.VOs;
using LMCommonage.Configurations;
using NumberHelper;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace LM.YF.K3Cloud.Plugin
{
    /// <summary>
    /// 鹿奔 240411
    /// </summary>
    [HotUpdate, Description("操作前计算结算单价（挂载到销售出库单）")]
    public class CalcSettlementPriceOperationServicePlugin : AbstractOperationServicePlugIn
    {
        #region MyRegion

        /// <summary>
        /// 销售组织
        /// </summary>
        private readonly ElementKeySchema FSaleOrgId = new ElementKeySchema
        {
            FormKey = "FSaleOrgId",
            DbKey = "FSALEORGID",
            OrmKey = "SaleOrgId"
        };

        /// <summary>
        /// 发货组织
        /// </summary>
        private readonly ElementKeySchema FStockOrgId = new ElementKeySchema
        {
            FormKey = "FStockOrgId",
            DbKey = "FSTOCKORGID",
            OrmKey = "StockOrgId"
        };

        /// <summary>
        /// 含税单价
        /// </summary>
        private readonly ElementKeySchema FTaxPrice = new ElementKeySchema
        {
            FormKey = "FTaxPrice",
            DbKey = "FTAXPRICE",
            OrmKey = "TaxPrice"
        };

        /// <summary>
        /// 结算单价
        /// </summary>
        private readonly ElementKeySchema F_RDLV_settlement_price = new ElementKeySchema
        {
            FormKey = "F_RDLV_settlement_price",
            DbKey = "F_RDLV_settlement_price",
            OrmKey = "F_RDLV_settlement_price"
        };

        /// <summary>
        /// 销售主体
        /// </summary>
        private readonly ElementKeySchema F_RDLV_saler2 = new ElementKeySchema
        {
            FormKey = "F_RDLV_saler2",
            DbKey = "F_RDLV_saler2",
            OrmKey = "F_RDLV_saler2"
        };

        /// <summary>
        /// 单据编号
        /// </summary>
        private readonly ElementKeySchema FBillNo = new ElementKeySchema
        {
            FormKey = "FBillNo",
            DbKey = "FBILLNO",
            OrmKey = "BillNo"
        };

        /// <summary>
        /// 物料编码
        /// </summary>
        private readonly ElementKeySchema FMaterialID = new ElementKeySchema
        {
            FormKey = "FMaterialID",
            DbKey = "FMATERIALID",
            OrmKey = "MaterialID"
        };

        /// <summary>
        /// 币别
        /// </summary>
        private readonly ElementKeySchema FSettleCurrID = new ElementKeySchema
        {
            FormKey = "FSettleCurrID",
            DbKey = "FSETTLECURRID",
            OrmKey = "SettleCurrID"
        };

        /// <summary>
        /// 汇率
        /// </summary>
        private readonly ElementKeySchema FExchangeRate = new ElementKeySchema
        {
            FormKey = "FExchangeRate",
            DbKey = "FEXCHANGERATE",
            OrmKey = "ExchangeRate"
        };

        /// <summary>
        /// 结算系数
        /// </summary>
        private readonly ElementKeySchema F_RDLV_coefficient = new ElementKeySchema
        {
            FormKey = "F_RDLV_coefficient",
            DbKey = "F_RDLV_COEFFICIENT",
            OrmKey = "F_RDLV_coefficient"
        };

        /// <summary>
        /// 明细单据体
        /// </summary>
        private readonly ElementKeySchema FEntity = new ElementKeySchema
        {
            FormKey = "FEntity",
            DbKey = "T_SAL_OUTSTOCKENTRY",
            OrmKey = "SAL_OUTSTOCKENTRY"
        };

        /// <summary>
        /// 财务信息单据体
        /// </summary>
        private readonly ElementKeySchema SubHeadEntity = new ElementKeySchema
        {
            FormKey = "SubHeadEntity",
            DbKey = "T_SAL_OUTSTOCKFIN",
            OrmKey = "SAL_OUTSTOCKFIN"
        };

        /// <summary>
        /// 明细单据体-海空运费
        /// </summary>
        private readonly ElementKeySchema F_QLTK_SeaAirFreight = new ElementKeySchema
        {
            FormKey = "F_QLTK_SeaAirFreight",
            DbKey = "F_QLTK_SEAAIRFREIGHT",
            OrmKey = "F_QLTK_SeaAirFreight"
        };

        /// <summary>
        /// 明细单据体-保费
        /// </summary>
        private readonly ElementKeySchema F_QLTK_PREMIUM = new ElementKeySchema
        {
            FormKey = "F_QLTK_PREMIUM",
            DbKey = "F_QLTK_PREMIUM",
            OrmKey = "F_QLTK_PREMIUM"
        };

        /// <summary>
        /// 明细单据体-佣金
        /// </summary>
        private readonly ElementKeySchema F_QLTK_Commission = new ElementKeySchema
        {
            FormKey = "F_QLTK_Commission",
            DbKey = "F_QLTK_COMMISSION",
            OrmKey = "F_QLTK_Commission"
        };

        /// <summary>
        /// 明细单据体-其他1
        /// </summary>
        private readonly ElementKeySchema F_QLTK_Other1 = new ElementKeySchema
        {
            FormKey = "F_QLTK_Other1",
            DbKey = "F_QLTK_OTHER1",
            OrmKey = "F_QLTK_Other1"
        };

        /// <summary>
        /// 计价数量
        /// </summary>
        private readonly ElementKeySchema FPriceUnitQty = new ElementKeySchema
        {
            FormKey = "FPriceUnitQty",
            DbKey = "FPRICEUNITQTY",
            OrmKey = "PriceUnitQty"
        };

        /// <summary>
        /// 税率
        /// </summary>
        private readonly ElementKeySchema FEntryTaxRate = new ElementKeySchema
        {
            FormKey = "FEntryTaxRate",
            DbKey = "FTAXRATE",
            OrmKey = "TaxRate"
        };

        #endregion

        public override void OnPreparePropertys(PreparePropertysEventArgs e)
        {
            base.OnPreparePropertys(e);

            e.FieldKeys.Add(FStockOrgId.FormKey);
            e.FieldKeys.Add(FTaxPrice.FormKey);
            e.FieldKeys.Add(F_RDLV_settlement_price.FormKey);
            e.FieldKeys.Add(F_RDLV_saler2.FormKey);
            e.FieldKeys.Add(FBillNo.FormKey);
            e.FieldKeys.Add(FMaterialID.FormKey);
            e.FieldKeys.Add(FSettleCurrID.FormKey);
            e.FieldKeys.Add(FExchangeRate.FormKey);
            e.FieldKeys.Add(F_RDLV_coefficient.FormKey);
        }

        public override void BeforeExecuteOperationTransaction(BeforeExecuteOperationTransaction e)
        {
            base.BeforeExecuteOperationTransaction(e);

            var failureList = new List<string>();
            foreach (var row in e.SelectedRows)
            {
                var failure = BeforeExecuteOperationTransaction(row);
                if (failure != null)
                {
                    failureList.Add(failure);
                }
            }
            if (failureList.Count > 0)
            {
                throw new KDBusinessException(null, string.Join("\r\n", failureList));
            }
        }

        private string BeforeExecuteOperationTransaction(ExtendedDataEntity row)
        {
            var dataEntity = row.DataEntity;
            var objSaleOrg = dataEntity[FSaleOrgId.OrmKey] as DynamicObject;
            var objSaleOrgName = (objSaleOrg?["Name"] as LocaleValue)?[2052];
            var objStockOrg = dataEntity[FStockOrgId.OrmKey] as DynamicObject;
            var stockOrgName = (objStockOrg?["Name"] as LocaleValue)?[2052];

            if (!(/*new string[] { "利民控股集团股份有限公司", "河北威远生物化工有限公司" }.Contains(objSaleOrgName)
                && */!stockOrgName.Equals(objSaleOrgName)))
            {
                return null;
            }

            var stockOrgId = Convert.ToInt32(objStockOrg["Id"]);
            var saleOrgId = Convert.ToInt32(objSaleOrg["Id"]);
            var salerId = Convert.ToInt32((dataEntity[F_RDLV_saler2.OrmKey] as DynamicObject)?["Id"]);
            if (stockOrgId == 0 || saleOrgId == 0 || salerId == 0)
            {
                return null;
            }

            var exchangeRate = 1M;// 汇率
            var finEntities = dataEntity[SubHeadEntity.OrmKey] as DynamicObjectCollection;
            var finEntity = finEntities[0];
            var settleCurr = Convert.ToInt32((finEntity[FSettleCurrID.OrmKey] as DynamicObject)?["Id"]);
            var isCny = settleCurr == 1;// 是否为人民币
            if (!isCny)
            {
                exchangeRate = Convert.ToDecimal(finEntity[FExchangeRate.OrmKey]);
            }
            var entries = dataEntity[FEntity.OrmKey] as DynamicObjectCollection;
            var entryDataCount = entries.Count;

            var vo = new avnn1
            {
                EntryDataCount = entryDataCount,
                ExchangeRate = exchangeRate,
                SaleOrgId = saleOrgId,
                SalerId = salerId,
                StockOrgId = stockOrgId
            };
            var vo2 = new vna1
            {
                GetInputs = entryIndex =>
                {
                    var entry = entries[entryIndex];
                    return new smznb111
                    {

                        Commission = Convert.ToDecimal(entry[F_QLTK_Commission.OrmKey]),
                        OtherFee = Convert.ToDecimal(entry[F_QLTK_Other1.OrmKey]),
                        Premium = Convert.ToDecimal(entry[F_QLTK_PREMIUM.OrmKey]),
                        PriceQty = Convert.ToDecimal(entry[FPriceUnitQty.OrmKey]),
                        SaFreight = Convert.ToDecimal(entry[F_QLTK_SeaAirFreight.OrmKey]),
                        TaxPrice = Convert.ToDecimal(entry[FTaxPrice.OrmKey]),
                        MaterialId = Convert.ToInt32((entry[FMaterialID.OrmKey] as DynamicObject)?["Id"]),
                        TaxRate = Convert.ToDecimal(entry[FEntryTaxRate.OrmKey])
                    };
                },
                OnCalculated = (settlementPrice, coefficient, entryIndex) =>
                {
                    var entry = entries[entryIndex];
                    var entryId = Convert.ToInt32(entry["Id"]);
                    entry[F_RDLV_coefficient.OrmKey] = coefficient.ToString();
                    entry[F_RDLV_settlement_price.OrmKey] = settlementPrice.ToString();
                    DBUtils.Execute(Context, $@"update T_SAL_OUTSTOCKENTRY
                    set F_RDLV_COEFFICIENT = {coefficient}, F_RDLV_SETTLEMENT_PRICE = {settlementPrice}
                    where FENTRYID = {entryId};");
                }
            };
            var failure = CalcSettlementPrice(Context, vo, vo2);

            if (!failure.Successful)
            {
                var billNo = dataEntity[FBillNo.OrmKey]?.ToString();
                return $"销售出库单【{billNo}】计算结算单价失败：{failure.Message}";
            }

            return null;
        }

        /// <summary>
        /// 计算结算单价
        /// </summary>
        /// <param name="context"></param>
        /// <param name="stockOrgId">供货组织</param>
        /// <param name="saleOrgId">销售组织</param>
        /// <param name="salerId">销售主体</param>
        /// <param name="getInputs">获取计算参数（分录索引）</param>
        /// <param name="onCalculated">结算单价，系数，分录数据</param>
        /// <returns></returns>
        public static Result CalcSettlementPrice(Context context, avnn1 vo, vna1 extraFuncs)
        {
            // 获取供货组织、销售组织、销售主体对应的整体系数
            var coefficientDataCollection = DBUtils.ExecuteDynamicObject(context, $@"
                select top 1 FID, F_RDLV_DEFAULT_COEFFICIENT
                from RDLV_t_interorg_prc_sch
                where FDOCUMENTSTATUS = 'C'
                    and F_RDLV_ORG = {vo.StockOrgId}-- 供货组织
                    and F_QLTK_SALEORG = {vo.SaleOrgId}-- 销售组织
                    and F_RDLV_SALER = {vo.SalerId}-- 销售主体
                order by FID desc;");
            if (!(coefficientDataCollection?.Count > 0))
            {
                return new Result
                {
                    Message = $"未获取到与供货组织&销售组织&销售主体相匹配的价目表！",
                    Successful = true
                };
            }

            // 获取组织信息
            var orgs = DBUtils.ExecuteDynamicObject(context
                , $@"select a.FORGID, b.FNAME
                from T_ORG_Organizations as a
                inner join T_ORG_Organizations_L as b on b.FLOCALEID = 2052 and b.FORGID = a.FORGID
                where a.FORGID in ({vo.StockOrgId}, {vo.SaleOrgId});");
            var stockOrgName = orgs
                .Where(o => Convert.ToInt32(o["FORGID"]) == vo.StockOrgId)
                .Select(o => o["FNAME"].ToString())
                .FirstOrDefault();
            var saleOrgName = orgs
                .Where(o => Convert.ToInt32(o["FORGID"]) == vo.SaleOrgId)
                .Select(o => o["FNAME"].ToString())
                .FirstOrDefault();

            // 取出系数单内码、默认系数
            var coefficientData = coefficientDataCollection.First();
            var coefficientId = Convert.ToInt32(coefficientData["FID"]);
            var defaultCoefficient = Convert.ToDecimal(coefficientData["F_RDLV_DEFAULT_COEFFICIENT"]);

            // 如果没有传入自定义公式，则使用默认公式
            var calcAmount = new Func<smznb111, int, decimal>((inputs, i) =>
            {
                // 默认单价为含税单价，所以赋值税率为0，防止后续1+税率时，重复计算税额
                var taxRate = 0M;
                if (inputs.TaxRate == 0)
                {
                    // 如果没有税率，则含税单价其实是不含税单价，所以需要从物料里取其默认税率，重新算其税额
                    taxRate = DBUtils.ExecuteScalar(context, $@"select b.FTAXRATE
                        from T_BD_MATERIALBASE as a
                        inner join T_BD_TAXRATE as b on b.FID = a.FTAXRATEID
                        where a.FMATERIALID = {inputs.MaterialId};", 0M);
                    taxRate /= 100;
                }

                // 价税合计
                var taxAmount = inputs.TaxPrice * inputs.PriceQty;
                // 金额
                decimal amount;
                // 结算金额（税率大于0，是国内业务）
                if ("河北威远生物化工有限公司".Equals(saleOrgName)
                    && "内蒙古新威远生物化工有限公司".Equals(stockOrgName)
                    && inputs.TaxRate > 0)
                {
                    //amount = taxAmount - inputs.Discount;
                    amount = taxAmount;
                }
                else
                {
                    // 其它组织的业务需减去运保佣，并最终再减去其它费用
                    amount = taxAmount /*- inputs.Discount*/ - inputs.SaFreight - inputs.Premium - inputs.Commission - inputs.OtherFee;
                }
                if (vo.LocalCurrId == KDConfigurations.CNY_ID)
                {
                    // 如果是人民币，则换算成人民币并计算税后
                    amount *= vo.ExchangeRate * (1 + taxRate);
                }

                return amount;
            });

            // 遍历单据的分录
            for (int i = 0; i < vo.EntryDataCount; i++)
            {
                // 获取计算所需的相关数据
                var inputs = extraFuncs.GetInputs(i);

                // 计算原金额
                var amount = calcAmount(inputs, i);

                // 获取对应物料的精确系数，作为首选系数
                var coefficientString = DBUtils.ExecuteScalar<string>(context
                    , $@"select top 1 F_RDLV_COEFFICIENT
                    from RDLV_t_interorg_ps_entry
                    where 1 = 1
                    and FID = {coefficientId}
                    and F_RDLV_MATERIAL in (
	                    select FMATERIALID
	                    from T_BD_MATERIAL
	                    where FNUMBER = (
		                    select FNUMBER
		                    from T_BD_MATERIAL
		                    where FMATERIALID = {inputs.MaterialId}
	                    )
                    )
                    order by FID desc;", default);
                // 最终系数
                var coefficient = coefficientString == null ? defaultCoefficient : Convert.ToDecimal(coefficientString);

                // 最终结算金额
                var settlementAmount = amount * coefficient;
                // 最终结算单价（使用分数计算，避免精度不准确）
                var fracSettlementPrice = Fraction.FromDecimal(settlementAmount) / inputs.PriceQty;
                var settlementPrice = fracSettlementPrice.ToDecimal();
                extraFuncs.OnCalculated?.Invoke(settlementPrice, coefficient, i);
            }

            return new Result
            {
                Successful = true
            };
        }
    }
}
